#include<strings.h>
#include<string.h>
#include<stdexcept>
#include"MEMREF.h"

using namespace std;
bool GetBinaryEntry(std::ifstream &log_file, std::unique_ptr<char[]> &buf) {
	assert(log_file.is_open());
	log_file.read(buf.get(), sizeof(MA));	
	if (log_file.gcount() != sizeof(MA)) {
		if (log_file.eof()) return false;
		else throw std::runtime_error("reach unexpected EOF.");
	}

	MA *pref = (MA *)buf.get();
	if (!IsBinaryPSBoundary(*pref) && !IsBinaryCSBoundary(*pref))
		return true;
	uint32_t extra_len = pref->mode_end;
	if (extra_len <= 0)
		return true;
	else {
		std::unique_ptr<char[]> big_buf(new char[sizeof(MA) + extra_len]);
		memcpy(big_buf.get(), buf.get(), sizeof(MA));
		log_file.read(big_buf.get() + sizeof(MA), extra_len);
		if (log_file.gcount() != extra_len)
			throw std::runtime_error("reach unexpected end of file while getting PS boundary.");
		buf = std::move(big_buf);
		return true;
	}
}

void PutBinaryBoundary(std::ofstream &log_file, MEMREF::BoundaryType bType,
		const string &data)
{
	assert(log_file.is_open());
	size_t len = data.length();
	size_t allocSize = sizeof(MA) + len + 1;
	char *buf = new char[allocSize];
	MA *ma = (MA *)buf;
	ma->start = (uint64_t)bType;
	*(uint64_t *)(&ma->mode_end) = len + 1;
	memcpy(buf + sizeof(MA), data.c_str(), len + 1);
	log_file.write(buf, allocSize);
	delete [] buf;
}

void PutTextBoundary(std::ofstream &log_file, MEMREF::BoundaryType bType,
		const string &data) {
	string prefix;
	switch(bType) {
		case MEMREF::ENTER_PS:
			prefix = "Enter PS ";
			break;
		case MEMREF::LEAVE_PS:
			prefix = "Leave PS ";
			break;
		case MEMREF::ENTER_CS:
			prefix = "Enter CS ";
			break;
		case MEMREF::LEAVE_CS:
			prefix = "Leave CS ";
			break;
		default:
			printf("Unknown boundary.\n");
			return;
	}
	log_file << prefix << data << '\n';
}
